﻿#region Usings
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.Reflection;
using System.ServiceModel.DomainServices.Client;
using System.Windows;
using System.Windows.Controls;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using InsuranceAdjuster;
using InsuranceAdjuster.Helpers;
using InsuranceAdjuster.OccasionallyConnected;
using InsuranceAdjuster.OccasionallyConnected.Messages;
using InsuranceAdjuster.Services;
using InsuranceAdjuster.Web.Models;
using Papa.Common;
#endregion
namespace InsuranceAdjuster.ViewModels {
    public class AdjusterDashboardViewModel : ViewModelBase {

        public AdjusterDashboardViewModel(IPageConductor pageConductor) {
            PageConductor = pageConductor;
            Initialize();
            // Initial data load
            this.EntityManager.ProcessMessage(new GetAppointmentsMessage());
        }

        protected override void OnEntityChanged(Guid entityGuid, Type entityType, ChangeOperation changeOperation, Origin changeOrigin, IEntity entity) {

            // Merge results into the current collection of Appointments

            if (entityType == typeof(AdjusterAppointment)) {
                if (changeOperation == ChangeOperation.Update || 
                    changeOperation == ChangeOperation.Read) {
                
                    // Make sure this appointment is in our list
                    var changedAppointment = entity as AdjusterAppointment;

                    bool ExistingAppointmentFound = false;

                    // Loop through the ViewModel appointments
                    for (int x = 0; x < this.Appointments.Count; x++) {
                        // update if we already have it 
                        if (this.Appointments[x].AppointmentGuid == changedAppointment.AppointmentGuid) {
                            this.Appointments[x] = changedAppointment;

                            ExistingAppointmentFound = true;
                            break;
                        }
                    }

                    if (this.SelectedAppointment != null &&
                        this.SelectedAppointment.AppointmentGuid == changedAppointment.AppointmentGuid) {

                        // Update the selected Appointment
                        this.SelectedAppointment = changedAppointment;
                    }

                    // If it wasn't in the list, add it
                    if (!ExistingAppointmentFound) {
                        this.Appointments.Add(changedAppointment);
                    }
                    RaisePropertyChanged("Appointments");

                } else if (changeOperation == ChangeOperation.Delete) {

                    // Remove this appointment from our list
                    for (int x = 0; x < Appointments.Count; x++) {
                        if (Appointments[x].AppointmentGuid == entityGuid) {
                            Appointments.Remove(Appointments[x]);
                            break;
                        }
                    }
                    RaisePropertyChanged("Appointments");
                }
                
            } else if (entityType == typeof(Claim)
                          && SelectedAppointment != null
                          && entityGuid == SelectedAppointment.ClaimGuid) {
                // Update the selected claim
                SelectedClaim = entity as Claim;
                FillClaimDetails();
            } 
        }

        #region Initializers
        protected Services.IPageConductor PageConductor { get; set; }
        protected Services.IInsuranceAdjusterDataService DataService { get; set; }

        public RelayCommand EditAppointmentCommand { get; set; }
        public RelayCommand SaveAppointmentCommand { get; set; }

        private void Initialize() {
            RegisterCommands();
            PropertyChanged += (o, e) => OnPropertyChanged(e.PropertyName);

            this.Appointments.CollectionChanged += (o, e) => {
                RaisePropertyChanged("Appointments");
            };
        }
        protected override void RegisterCommands() {
            EditAppointmentCommand = new RelayCommand(OnEditAppointment);
            SaveAppointmentCommand = new RelayCommand(OnSaveAppointment, () => HasChanges);
        }

        public void OnGotFocus() {
            if (null == SelectedAppointment && this.Appointments.Count > 0) {
                this.SelectedAppointment = this.Appointments[0];
            }
        }
        
        private void OnPropertyChanged(string propertyName) {
            switch (propertyName) {
                case "Appointments":
                    if (SelectedAppointment == null && Appointments.Count > 0)
                        SelectedAppointment = Appointments[0];
                    break;
            }
        }
        #endregion
        
        #region Edit & Savving
        private void OnEditAppointment() {
            //TODO: May need to assure the Claim object gets loaded
            // was thinking of doing individual loads, based on the Claim_ID
            Messenger.Default.Send(new Messages.LaunchClaimMessage() { Claim = SelectedAppointment.Claim });
        }

        private void OnSaveAppointment() {
            DataService.SaveAll(SaveAppointmentCallback, null);
        }

        private void SaveAppointmentCallback(SubmitOperation op) {
            string msg = op.HasError ? "Save was unsuccessful" : "Save was successful";
            var dialogMessage = new Messages.SavedAdjusterAppointmentDialogMessage(msg, "Save");
            Messenger.Default.Send(dialogMessage);
        }
        #endregion

        #region Bindable Properties
        private ObservableCollection<AdjusterAppointment> _appointments = new ObservableCollection<AdjusterAppointment>();
        public ObservableCollection<AdjusterAppointment> Appointments {
            get { return _appointments; }
            set {
                _appointments = value;
                RaisePropertyChanged("Appointments");
            }
        }

        private AdjusterAppointment _selectedAppointment;
        public AdjusterAppointment SelectedAppointment {
            get { return _selectedAppointment; }
            set {
                _selectedAppointment = value;
                // If using pure Selection Binding, load the claim here
                //LoadClaim();
                RaisePropertyChanged("SelectedAppointment");
            }
        }

        private Claim _selectedClaim;
        public Claim SelectedClaim {
            get {
                return _selectedClaim;
            }
            set {
                _selectedClaim = value;
                RaisePropertyChanged("SelectedClaim");
            }
        }

        private bool _hasChanges;
        public bool HasChanges {
            get { return _hasChanges; }
            set {
                _hasChanges = value;
                RaisePropertyChanged("HasChanges");
            }
        }
        #endregion

        #region ICustomTypeProvider

        public ObservableCollection<Field> ClaimDisplayFields {
            get { return ClaimSchema.claimDisplayFields; }
            set {
                ClaimSchema.claimDisplayFields = value;
                RaisePropertyChanged("ClaimDisplayFields");
            }
        }

        private ClaimDetails _claimDetails { get; set; }

        public ObservableCollection<UIElement> DetailControls {
            get {
                var MyDetails = new ObservableCollection<UIElement>();

                if (_claimDetails == null)
                    return MyDetails;

                foreach (PropertyInfo prop in _claimDetails.GetAllProperties()) {
                    Label propDescription = new Label();
                    object[] attr = prop.GetCustomAttributes(false);
                    propDescription.Content = ((DisplayAttribute)attr[0]).Name;
                    propDescription.Style = (Style)App.Current.Resources["IncidentDetailsLabel"];

                    TextBlock propValue = new TextBlock();

                    var tempa = prop.GetValue(_claimDetails, null);
                    if (tempa != null)
                        propValue.Text = tempa.ToString();

                    //propValue.Text = prop.GetValue(_claimDetails, null).ToString();
                    MyDetails.Add(propDescription);
                    MyDetails.Add(propValue);
                }
                return MyDetails;
            }
        }

        /// <summary>
        /// Creating object shape and setting values 
        /// with ICustomTypeProvider interface
        /// </summary>
        public void FillClaimDetails() {
            // Construct the ICustomTypeProvider Object
            ClaimDetails.ClearCustomProperties();

            foreach (Field item in ClaimDisplayFields) {
                if (item.Selected == true) {
                    DisplayAttribute attr = new DisplayAttribute();
                    attr.Name = item.Description;
                    PropertyInfo prop = typeof(Claim).GetProperty(((Field)item).FieldName);

                    if (prop == null) {
                        // This prop is no longer valid, please fix it in the list of DisplayFields
                        continue;
                    } else
                        ClaimDetails.AddProperty(prop.Name, prop.PropertyType, new List<Attribute> { attr });
                }
            }

            if (SelectedClaim == null) {
                RaisePropertyChanged("DetailControls");
                return;
            }

            _claimDetails = new ClaimDetails();
            foreach (PropertyInfo prop in _claimDetails.GetAllProperties()) {
                _claimDetails.SetCustomPropertyValue(prop.Name,
                    typeof(Claim).GetProperty(prop.Name).GetValue(SelectedClaim, null));
            }
            RaisePropertyChanged("DetailControls");
        }

        public void OnAppointmentChanged() {
            if (SelectedAppointment == null)
                return;
            if (SelectedClaim != null &&
                SelectedAppointment.ClaimGuid == SelectedClaim.ClaimGuid)
                return;

            this.EntityManager.ProcessMessage(new GetClaimMessage(SelectedAppointment.ClaimGuid));
        }

        #endregion
    }
}
